"""
消息推送相关的数据模型
对应数据库表: base_notification
"""
import json
from datetime import datetime
from enum import Enum
from typing import Optional, Dict, Any, List

from pydantic import BaseModel, Field, validator, ConfigDict


class NotificationType(str, Enum):
    """
    消息类型枚举
    """
    SYSTEM = "SYSTEM"  # 系统消息
    ALARM = "ALARM"  # 告警消息
    DEVICE = "DEVICE"  # 设备消息
    WORK_ORDER = "WORK_ORDER"  # 工单消息
    USER = "USER"  # 用户消息
    MAINTENANCE = "MAINTENANCE"  # 维护消息


class NotificationPriority(str, Enum):
    """
    消息优先级枚举
    """
    LOW = "LOW"  # 低优先级
    NORMAL = "NORMAL"  # 普通优先级
    HIGH = "HIGH"  # 高优先级
    URGENT = "URGENT"  # 紧急


class NotificationStatus(int, Enum):
    """
    消息状态枚举
    """
    UNREAD = 0  # 未读
    READ = 1  # 已读


class NotificationBase(BaseModel):
    """
    消息通知基础模型
    """
    user_id: int = Field(..., description="接收用户ID", gt=0)
    type: NotificationType = Field(..., description="消息类型")
    priority: NotificationPriority = Field(NotificationPriority.NORMAL, description="优先级")
    title: str = Field(..., description="消息标题", max_length=128)
    content: Optional[str] = Field(None, description="消息内容")
    data_json: Optional[Dict[str, Any]] = Field(None, description="扩展数据")
    expire_time: Optional[datetime] = Field(None, description="过期时间")

    @validator('title')
    def validate_title(cls, v):
        """验证消息标题"""
        if not v or not v.strip():
            raise ValueError("消息标题不能为空")
        return v.strip()

    @validator('content')
    def validate_content(cls, v):
        """验证消息内容"""
        if v and len(v.strip()) == 0:
            return None
        return v.strip() if v else v

    @validator('data_json', pre=True)
    def validate_data_json(cls, v):
        """验证扩展数据JSON"""
        if v is None:
            return v
        if isinstance(v, str):
            try:
                return json.loads(v)
            except json.JSONDecodeError:
                raise ValueError("扩展数据必须是有效的JSON格式")
        return v

    @validator('expire_time')
    def validate_expire_time(cls, v):
        """验证过期时间"""
        if v and v <= datetime.now():
            raise ValueError("过期时间必须晚于当前时间")
        return v


class Notification(NotificationBase):
    """
    消息通知完整模型（包含数据库字段）
    """
    id: int = Field(..., description="主键ID")
    read_flag: NotificationStatus = Field(NotificationStatus.UNREAD, description="是否已读")
    gmt_create: datetime = Field(..., description="创建时间")

    @property
    def is_read(self) -> bool:
        """是否已读"""
        return self.read_flag == NotificationStatus.READ

    @property
    def is_expired(self) -> bool:
        """是否已过期"""
        if not self.expire_time:
            return False
        return datetime.now() > self.expire_time

    @property
    def is_urgent(self) -> bool:
        """是否紧急消息"""
        return self.priority == NotificationPriority.URGENT

    @property
    def age_minutes(self) -> int:
        """消息年龄（分钟）"""
        return int((datetime.now() - self.gmt_create).total_seconds() / 60)

    model_config = ConfigDict(from_attributes=True)


class NotificationWithUser(Notification):
    """
    包含用户信息的消息通知模型
    用于管理端查看消息时显示用户名
    """
    username: Optional[str] = Field(None, description="用户名")
    user_name: Optional[str] = Field(None, description="用户姓名")


class NotificationSummary(BaseModel):
    """
    消息摘要模型
    用于显示用户的消息统计信息
    """
    total_count: int = Field(0, description="总消息数")
    unread_count: int = Field(0, description="未读消息数")
    urgent_count: int = Field(0, description="紧急消息数")
    expired_count: int = Field(0, description="已过期消息数")

    # 按类型统计
    system_count: int = Field(0, description="系统消息数")
    alarm_count: int = Field(0, description="告警消息数")
    device_count: int = Field(0, description="设备消息数")
    work_order_count: int = Field(0, description="工单消息数")

    @property
    def read_count(self) -> int:
        """已读消息数"""
        return self.total_count - self.unread_count

    @property
    def read_rate(self) -> float:
        """已读率"""
        if self.total_count == 0:
            return 0.0
        return round((self.read_count / self.total_count) * 100, 2)


class NotificationGroup(BaseModel):
    """
    消息分组模型
    按日期或类型分组显示消息
    """
    group_key: str = Field(..., description="分组键（如日期或类型）")
    group_name: str = Field(..., description="分组名称")
    count: int = Field(..., description="消息数量")
    unread_count: int = Field(0, description="未读消息数")
    notifications: List[Notification] = Field(default_factory=list, description="消息列表")

    @property
    def has_unread(self) -> bool:
        """是否有未读消息"""
        return self.unread_count > 0


class NotificationTemplate(BaseModel):
    """
    消息模板模型
    用于定义常用的消息模板
    """
    type: NotificationType = Field(..., description="消息类型")
    priority: NotificationPriority = Field(..., description="优先级")
    title_template: str = Field(..., description="标题模板", max_length=128)
    content_template: Optional[str] = Field(None, description="内容模板")
    variables: List[str] = Field(default_factory=list, description="模板变量列表")

    def render(self, variables: Dict[str, Any]) -> tuple[str, Optional[str]]:
        """
        渲染模板

        Args:
            variables: 模板变量值

        Returns:
            tuple[str, Optional[str]]: (渲染后的标题, 渲染后的内容)
        """
        title = self.title_template
        content = self.content_template

        for key, value in variables.items():
            placeholder = f"{{{key}}}"
            title = title.replace(placeholder, str(value))
            if content:
                content = content.replace(placeholder, str(value))

        return title, content


class NotificationBatch(BaseModel):
    """
    批量消息模型
    用于批量发送消息
    """
    user_ids: List[int] = Field(..., description="接收用户ID列表", min_items=1)
    type: NotificationType = Field(..., description="消息类型")
    priority: NotificationPriority = Field(NotificationPriority.NORMAL, description="优先级")
    title: str = Field(..., description="消息标题", max_length=128)
    content: Optional[str] = Field(None, description="消息内容")
    data_json: Optional[Dict[str, Any]] = Field(None, description="扩展数据")
    expire_time: Optional[datetime] = Field(None, description="过期时间")

    @validator('user_ids')
    def validate_user_ids(cls, v):
        """验证用户ID列表"""
        if not v:
            raise ValueError("用户ID列表不能为空")
        if len(v) > 1000:
            raise ValueError("单次批量发送不能超过1000个用户")
        # 去重
        return list(set(v))

    @validator('title')
    def validate_title(cls, v):
        """验证消息标题"""
        if not v or not v.strip():
            raise ValueError("消息标题不能为空")
        return v.strip()


class NotificationFilter(BaseModel):
    """
    消息查询过滤器
    """
    user_id: Optional[int] = Field(None, description="用户ID")
    type: Optional[NotificationType] = Field(None, description="消息类型")
    priority: Optional[NotificationPriority] = Field(None, description="优先级")
    read_flag: Optional[NotificationStatus] = Field(None, description="读取状态")
    start_time: Optional[datetime] = Field(None, description="开始时间")
    end_time: Optional[datetime] = Field(None, description="结束时间")
    keyword: Optional[str] = Field(None, description="标题或内容关键词", max_length=50)
    include_expired: bool = Field(True, description="是否包含已过期消息")

    @validator('keyword')
    def validate_keyword(cls, v):
        """验证关键词"""
        if v and not v.strip():
            raise ValueError("关键词不能为空字符串")
        return v.strip() if v else v

    @validator('end_time')
    def validate_time_range(cls, v, values):
        """验证时间范围"""
        if v and 'start_time' in values and values['start_time']:
            if v <= values['start_time']:
                raise ValueError("结束时间必须晚于开始时间")
        return v


# 预定义的消息模板
NOTIFICATION_TEMPLATES = {
    "ALARM_DEVICE_OFFLINE": NotificationTemplate(
        type=NotificationType.ALARM,
        priority=NotificationPriority.HIGH,
        title_template="设备离线告警 - {device_name}",
        content_template="设备 {device_name}（编号：{device_id}）已离线，请及时检查设备状态。",
        variables=["device_name", "device_id"]
    ),
    "WORK_ORDER_ASSIGNED": NotificationTemplate(
        type=NotificationType.WORK_ORDER,
        priority=NotificationPriority.NORMAL,
        title_template="新工单分配 - {work_order_title}",
        content_template="您有新的工单需要处理：{work_order_title}，工单编号：{work_order_no}，请及时处理。",
        variables=["work_order_title", "work_order_no"]
    ),
    "SYSTEM_MAINTENANCE": NotificationTemplate(
        type=NotificationType.SYSTEM,
        priority=NotificationPriority.LOW,
        title_template="系统维护通知",
        content_template="系统将于 {maintenance_time} 进行维护，预计耗时 {duration}，请提前做好准备。",
        variables=["maintenance_time", "duration"]
    ),
    "DEVICE_MALFUNCTION": NotificationTemplate(
        type=NotificationType.DEVICE,
        priority=NotificationPriority.URGENT,
        title_template="设备故障紧急通知 - {device_name}",
        content_template="设备 {device_name} 发生故障，故障代码：{error_code}，请立即处理！",
        variables=["device_name", "error_code"]
    )
}


def get_notification_template(template_key: str) -> Optional[NotificationTemplate]:
    """
    获取消息模板

    Args:
        template_key: 模板键名

    Returns:
        NotificationTemplate: 消息模板，不存在则返回None
    """
    return NOTIFICATION_TEMPLATES.get(template_key)


def create_notification_from_template(
        template_key: str,
        user_id: int,
        variables: Dict[str, Any],
        data_json: Optional[Dict[str, Any]] = None,
        expire_time: Optional[datetime] = None
) -> Optional[NotificationBase]:
    """
    从模板创建消息

    Args:
        template_key: 模板键名
        user_id: 接收用户ID
        variables: 模板变量值
        data_json: 扩展数据
        expire_time: 过期时间

    Returns:
        NotificationBase: 创建的消息对象，模板不存在则返回None
    """
    template = get_notification_template(template_key)
    if not template:
        return None

    title, content = template.render(variables)

    return NotificationBase(
        user_id=user_id,
        type=template.type,
        priority=template.priority,
        title=title,
        content=content,
        data_json=data_json,
        expire_time=expire_time
    )
